﻿/**
 * Copyright (C) 2012-2013 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Spi;

namespace NGuice.Inject.Internal
{
    /// <summary>
    /// 此工厂存在与一个父注入器中。当调用时，他从子注入器中解析获取他们的值
    /// <remarks>
    /// Notify方法将作为BindingProcessor的Creation事件加入
    /// </remarks>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal sealed class ExposedKeyFactory<T> : InternalFactory<T>
    {
        private readonly Key<T> key;
        private readonly IPrivateElements privateElements;
        private BindingImpl<T> delegatee;

        internal ExposedKeyFactory(Key<T> key, IPrivateElements privateElements)
        {
            this.key = key;
            this.privateElements = privateElements;
        }

        public void Notify(Errors errors)
        {
            InjectorImpl privateInjector = (InjectorImpl)privateElements.Injector;
            BindingImpl<T> explicitBinding = privateInjector.state.GetExplicitBinding(key);

            // validate that the child injector has its own factory. If the getInternalFactory() returns
            // this, then that child injector doesn't have a factory (and getExplicitBinding has returned
            // its parent's binding instead
            if (explicitBinding.InternalFactory == this)
            {
                errors.WithSource(explicitBinding.Source).ExposedButNotBound(key);
                return;
            }

            this.delegatee = explicitBinding;
        }

        public T Get(Errors errors, InternalContext context, Dependency dependency, bool linked)
        {
            return delegatee.InternalFactory.Get(errors, context, dependency, linked);
        }

        object InternalFactory.Get(Errors errors, InternalContext context, Dependency dependency, bool linked)
        {
            return Get(errors, context, dependency, linked);
        }
    }
}
